package com.recruit.g1.common.encoder;

import com.recruit.g1.common.enums.PassportResultEnum;
import com.recruit.g1.common.exception.BusinessException;
import com.recruit.g1.common.utils.JsonUtils;
import io.jsonwebtoken.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

@Slf4j
public class JwtEncoder<T> {

    private String secret;//密钥secret

    private static final String CLAIM_PAYLOAD = "payload";

    /**
     * 生成JWT（JSON Web Token）//生成jsonWeb令牌
     * @param payload
     * @return
     * @throws BusinessException
     */
    public String generateToken(T payload) throws BusinessException {
        Map<String, Object> claims = new HashMap<>();
        claims.put(CLAIM_PAYLOAD, JsonUtils.toJson(payload));
        JwtBuilder builder = null;
        try{//                                                  //用HS512算法和密钥secret对jwt令牌签名(加密)
            builder = Jwts.builder().setClaims(claims).signWith(SignatureAlgorithm.HS512,secret.getBytes(StandardCharsets.UTF_8));
        }catch (Exception e){
            //若签名失败，记录日志并抛出业务异常 TOKEN_GENERATE_FAILED；
            log.error("failed to create jwt builders,error message:{}",e.getMessage());
            throw new BusinessException(PassportResultEnum.TOKEN_GENERATE_FAILED);
        }//    调用JwtBuilder的compact()方法完成签名(加密)并生成jwt令牌
        return builder.compact();//返回生成的JWT字符串
    }


    /**
     * 从token中获取登录信息(检查用户是否登录过)： 从token中获取CLAIM_PAYLOAD看是否能获取到，若能获取到则表示之前登录过，则返回该信息；
     * @param token
     * @param clazz
     * @return
     * @throws BusinessException
     */
    public T getLoginFromToken(String token, Class<? extends T> clazz) throws BusinessException {
        Jws<Claims> jws = null;
        if (StringUtils.isEmpty(token)){//如果 token 为空，直接返回 null；
            return null;
        }
        try {//使用签名密钥解析 JWT token (失败则记录日志并抛出 JWT_PARSE_ERROR 异常)
            jws = Jwts.parser().setSigningKey(secret.getBytes(StandardCharsets.UTF_8)).parseClaimsJws(token);
        } catch(Exception e){
            //使用签名密钥解析 JWT token，失败则记录日志并抛出 JWT_PARSE_ERROR 异常；
            log.error("jwt parse error:{}",e.getMessage());
            throw new BusinessException(PassportResultEnum.JWT_PARSE_ERROR);
        }
        Claims claims = (Claims)jws.getBody();
        //从解析出的 Claims 中获取 payload 字段（JSON 字符串）
        String loginTokenJson_payLoad = (String)claims.get(CLAIM_PAYLOAD);
        //将解析出的json解析为String信息
        return JsonUtils.fromJson(loginTokenJson_payLoad, clazz);
    }

    /**
     * 获取密钥secret的值
     * @return
     */
    public String getSecret() {
        return secret;
    }

    /**
     * 给密钥secret赋值
     * @param secret
     */
    public void setSecret(String secret) {
        this.secret = secret;
    }
}
